package com.whq.common.http;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.whq.common.StringUtil;

/**
 * HttpClient工具类.
 *
 * @author wanghuaiqiang
 */
public class HttpClientUtil {
    private static final Log LOGGER = LogFactory.getLog(HttpClientUtil.class);
    private static final Logger LOGGER_THRIFT_REQUEST_RESPONSE = LoggerFactory.getLogger("logger_http_request_response");
    
    /**
     * 通过 GET 方式获取访问URL的结果内容
     * @param urlPrefix url前缀
     * @param paramsMap 参数
     * @param urlEncoder 是否需要urlEncoder
     * @param connectTimeoutMillisecond 链接超时毫秒数
     * @param getMethodTimeOutMillisecond get方式访问超时毫秒数
     * @return 页面内容字符串
     */
    public static String fetchStrByGetMethod(String urlPrefix, Map<String, String> paramsMap, boolean urlEncoder, int connectTimeoutMillisecond, int getMethodTimeOutMillisecond) {
    	String url = UrlUtil.generateUrl(urlPrefix, paramsMap, urlEncoder);
    	String response = fetchStrByGetMethod(url, connectTimeoutMillisecond, getMethodTimeOutMillisecond);
    	return response;
    }
    
    /**
     * 通过 GET 方式获取访问URL的结果内容
     * @param url
     * @param connectTimeoutMillisecond 链接超时毫秒数
     * @param getMethodTimeOutMillisecond get方式访问超时毫秒数
     * @return 页面内容字符串
     */
    public static String fetchStrByGetMethod(String url, int connectTimeoutMillisecond, int getMethodTimeOutMillisecond) {
        if (url == null) {
            return "";
        }
        url = url.trim();
        if ( (url.length() > 5) 
                && (url.substring(0, 5).equalsIgnoreCase("https")) 
                ) {
            ProtocolSocketFactory fcty = new MctSecureProtocolSocketFactory();
            Protocol.registerProtocol("https", new Protocol("https", fcty, 443));
        }
        
        HttpClient httpClient = new HttpClient();
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(connectTimeoutMillisecond);  
        
        // 创建GET方法的实例
        GetMethod getMethod = new GetMethod(url);
        getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, getMethodTimeOutMillisecond);
        getMethod.setFollowRedirects(false);
        // 使用系统提供的默认的恢复策略
        getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler());
        try {
            // 执行getMethod
            int statusCode = httpClient.executeMethod(getMethod);
            if (statusCode != HttpStatus.SC_OK) {
            	LOGGER.error("读取URL: " + url + "信息失败: " + getMethod.getStatusLine());
            	LOGGER_THRIFT_REQUEST_RESPONSE.info("request url[" + url + "] by get, response[]");
                return null;
            } else {
                // 读取内容
                byte[] responseBody = getMethod.getResponseBody();
                // 处理内容
                LOGGER_THRIFT_REQUEST_RESPONSE.info("request url[" + url + "] by get, response[" + new String(responseBody) + "]");
                return new String(responseBody);
            }
        } catch (HttpException e) {
            // 发生致命的异常，可能是协议不对或者返回的内容有问题
        	LOGGER.error("URL地址 : " + url + "有问题: " , e);
        } catch (IOException e) {
            // 发生网络异常
        	LOGGER.error("访问url:" + url + ", 发生网络异常 : " , e);
        } finally {
            // 释放连接
            getMethod.releaseConnection();
        }
        LOGGER_THRIFT_REQUEST_RESPONSE.info("request url[" + url + "] by get, response[]");
        return null;
    }
    
    /**
     * 通过 POST 方式获取访问URL的结果内容
     * @param url
     * @param paramMap
     * @param connectTimeoutMillisecond 链接超时毫秒数
     * @param getMethodTimeOutMillisecond get方式访问超时毫秒数
     * @return 页面内容字符串
     */
    public static String fetchStrByPostMethod(String url, Map<String, String> paramMap,  int connectTimeoutMillisecond, int getMethodTimeOutMillisecond) {
        if (url == null) {
            return "";
        }
        url = url.trim();
        if ( (url.length() > 5) 
                && (url.substring(0, 5).equalsIgnoreCase("https")) 
                ) {
            ProtocolSocketFactory fcty = new MctSecureProtocolSocketFactory();
            Protocol.registerProtocol("https", new Protocol("https", fcty, 443));
        }
        
        HttpClient httpClient = new HttpClient();
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(connectTimeoutMillisecond);  
        
        // 创建GET方法的实例
        PostMethod postMethod = new Utf8PostMethod(url);
        postMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, getMethodTimeOutMillisecond);
        
        // 加入参数
        if (paramMap != null) {
        	for (Iterator<String> iterator = paramMap.keySet().iterator(); iterator.hasNext();) {
                String paramName = (String) iterator.next();
                postMethod.setParameter(paramName, paramMap.get(paramName));
            }
        }
        
        postMethod.setFollowRedirects(false);
        // 使用系统提供的默认的恢复策略
        postMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler());
        try {
            // 执行getMethod
            int statusCode = httpClient.executeMethod(postMethod);
            if (statusCode != HttpStatus.SC_OK) {
            	LOGGER.error("提交信息到URL: " + url + "信息失败: " + postMethod.getStatusLine());
            	LOGGER_THRIFT_REQUEST_RESPONSE.info("request url[" + url + "] by post, params[" + paramMap + "], response[]");
                return null;
            } else {
                // 读取内容
                byte[] responseBody = postMethod.getResponseBody();
                // 处理内容
                LOGGER_THRIFT_REQUEST_RESPONSE.info("request url[" + url + "] by post, params[" + paramMap + "], response[" + new String(responseBody) + "]");
                return new String(responseBody);
            }
        } catch (HttpException e) {
            // 发生致命的异常，可能是协议不对或者返回的内容有问题
        	LOGGER.error("URL地址 : " + url + "有问题: " , e);
        } catch (IOException e) {
            // 发生网络异常
        	LOGGER.error("发生网络异常 : " , e);
        } finally {
            // 释放连接
            postMethod.releaseConnection();
        }
        LOGGER_THRIFT_REQUEST_RESPONSE.info("request url[" + url + "] by post, params[" + paramMap + "], response[]");
        return null;
    }
    
    /**
     * 解决POST参数乱码问题.
     *
     * @author wanghuaiqiang
     */
    public static class Utf8PostMethod extends PostMethod {
        public Utf8PostMethod(String url) {
            super(url);
        }

        @Override
        public String getRequestCharSet() {
            // return super.getRequestCharSet();
            return "UTF-8";
        }
    }
    
    public static String getRealRequestUrl(HttpServletRequest request) { 
    	String realRequestUrl = request.getHeader("x-real-request_url");  
        if (realRequestUrl == null || realRequestUrl.length() == 0 || "unknown".equalsIgnoreCase(realRequestUrl)) {  
            realRequestUrl = request.getHeader("X-Real-Request_Url");  
        }  
        
        if (realRequestUrl == null || realRequestUrl.length() == 0 || "unknown".equalsIgnoreCase(realRequestUrl)) {
        	realRequestUrl = request.getRequestURL().toString();
        }
        
        if (realRequestUrl == null) {
        	realRequestUrl = "";
        }
        
        if (realRequestUrl.contains("?")) {
        	String[] arrTmp = realRequestUrl.split("\\?");
        	if ( (arrTmp != null) && (arrTmp.length > 0) ) {
        		realRequestUrl = arrTmp[0];
        	}
        }
        
       return realRequestUrl;  
   } 
    
    public static String getRealIpAddr(HttpServletRequest request) { 
    	String ip = request.getHeader("x-real-ip"); 
    	if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("X-Real-IP");  
        } 
    	
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("x-forwarded-for");  
        }  
        
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("X-Forwarded-For");  
        } 
    	
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("Proxy-Client-IP");  
        }  
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("WL-Proxy-Client-IP");  
        }  
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
           ip = request.getRemoteAddr();  
       }  
        
       if (ip == null) {
    	   ip = "";
       }
       
       List<String> ipList = StringUtil.split2list(ip, "\\,");
       if ( (ipList == null) || (ipList.isEmpty()) ) {
    	   return ip;
       }
       return ipList.get(0);  
   }  
}
